/*----------------------------------------------------------------------------
 | Copyright (c) 2009 Matthew B. Brophy (matt@brophy.org).  
 | Liscense: MIT License (http://www.opensource.org/licenses/mit-license.php)
 |
 | $Id: ajax.js 16 2009-02-26 01:53:24Z matt@brophy.org $
 -----------------------------------------------------------------------------*/

if (typeof org == "undefined" || 
    org == null) { org = {}; }
if (typeof org.brophy == "undefined" || 
    org.brophy == null) { org.brophy = {}; }
if (typeof org.brophy.js == "undefined" || 
    org.brophy.js == null) { org.brophy.js = {}; }

/** 
 * @namespace 
 * @description Ajax namespace in the org.brophy.js JavaScript library 
 * @requires    This library requires the <a href="http://www.mochikit.com">
 *              MochiKit</a> JavaScript library 
 *              (version 1.4+).
 */
org.brophy.js.ajax = {}; 


/**
 * @constructor
 * @description The ReplyManager is a class used to handle AJAX XML 
 *              responses from the server.<br/><br/>
 * 
 * Each reply is expected to be of the form:    <br/>
 * <pre>
 * &lt;?xml version='1.0' encoding='utf-8'?&gt; 
 * &lt;OBJResponse&gt;                          
 * &nbsp;&nbsp;[ Some XML tree ]                
 * &lt;/OBJResponse&gt;                         
 * </pre>                                       
 * <br/>
 *
 * This class for now only supports retreiving top level element values, 
 * those that are direct children of the OBJResponse element.  Future work
 * will support retreiving children trees and grandchild values.
 */
org.brophy.js.ajax.ReplyManager = function() 
{
  this.xml = null;
  bindMethods(this);
}
 
/**
 * @member org.brophy.js.ajax.ReplyManager
 * @description Read the XML response document from the AJAX request
 * @param  res  The responseXML document from the server
 * @return TRUE if the document is valid and contains the approoriate 
 *         OBJResponse element, FALSE otherwise.
 * @type boolean
 */
org.brophy.js.ajax.ReplyManager.prototype.readXMLReply = function(res)
{
  if( !isUndefinedOrNull(res) &&
      !isUndefinedOrNull(res.responseXML) &&
      res.responseXML.getElementsByTagName("OBJResponse").length > 0 )
  {
    this.xml = res.responseXML;
    return true;
  }
  else
  {
    return false;
  }
}

/**
 * @member org.brophy.js.ajax.ReplyManager
 * @description Get the node value for a direct child node of name 'tagName' 
 *              of the OBJResponse element in the AJAX XML response
 * @param   tagName  The string value of the XML node conatinaing the desired
 *                   value
 * @returns The string node value of the requested node, or NULL if this node 
 *          does not exist.
 * @type    string
 */
org.brophy.js.ajax.ReplyManager.prototype.getChild = function(tagName)
{
  var nodes = this.xml.getElementsByTagName(tagName);
  if(nodes.length > 0)
  {
    return nodes[0].firstChild.nodeValue;
  }
  else
  {
    return null;
  }
}

/**
 * Generic function to send an AJAX request to the server and return a 
 * MochiKit.Async.Deferred object encapulating the request.  It should be 
 * noted that this function automatically appends a timestamp to the url 
 * to prevent browser caching of AJAX requests.
 *
 * @param  url    
 *           The base URL to send the request to.  This should be a Servlet 
 *           or script name, wihtout any attached patameters or values, or 
 *           a trailing question mark.  Example: "/scripts/ajax.php"
 * @param  okFunc 
 *           The function to be called upon a successful request.  This 
 *           function will be passed the {@link org.brophy.js.ajax.ReplyManager}
 *           object created for the response
 * @param  [keys = []] 
 *           An array of parameter keys/names to pass with the request.  It 
 *           is very useful to use the MochiKit formContents function to 
 *           generate this array.
 * @param  [vals = []]
 *           The corresonding array of values matching the keys. It 
 *           is very useful to use the MochiKit formContents function to 
 *           generate this array.
 * @param  [method = "GET"]  Either the string "GET" or "POST"
 * @return A MochiKit.Async.Deferred object encapulating the request, or NULL 
 *         if the request cannot be sent, or an error occurs in the response.
 * @type   MochiKit.Async.Deferred
 */
org.brophy.js.ajax.sendRequest = 
function(url, okFunc, keys, vals, method)
{
  // Initialize three optional parameters
  if(isUndefinedOrNull(keys))    { keys = []; }
  if(isUndefinedOrNull(vals))    { vals = []; }
  if(isUndefinedOrNull(method))  { method = "GET"; }

  // Must pass a url and a callback function
  if(isUndefinedOrNull(url))
    { return null; }

  if(isUndefinedOrNull(okFunc)) 
    { return null; } 

  var theKeys = [ "time" ];
  var theVals = [ new Date().getTime() ]

  while(keys.length > 0 && vals.length > 0)
  {
    theKeys.push(keys.shift());
    theVals.push(vals.shift());
  }

  var xmlHttp = getXMLHttpRequest();

  if(xmlHttp != null)  {
    var myDeferred;
    if(method.toUpperCase() == "GET")
    {
      xmlHttp.open("GET", url + "?" + queryString(theKeys,theVals),true);
      myDeferred = sendXMLHttpRequest(xmlHttp);
    }
    else
    { 
      xmlHttp.open("POST", url, true);
      xmlHttp.setRequestHeader("Content-Type", 
                               "application/x-www-form-urlencoded");
      myDeferred = sendXMLHttpRequest(xmlHttp, queryString(theKeys,theVals));
    }

    myDeferred.addCallback(
      function(res)
      {
        var r = new org.brophy.js.ajax.ReplyManager();
  
        if(r.readXMLReply(res))
          { okFunc(r); }
        else
          { alert("There was an error processing the AJAX response."); }
      });

    return myDeferred;
  } 
  return null;
}



